package ch.uzh.ifi.seal.ssqa.metrics;

import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.preference.IPreferenceStore;

import ch.uzh.ifi.seal.ssqa.SsqaPlugin;
import ch.uzh.ifi.seal.ssqa.model.Coupling;
import ch.uzh.ifi.seal.ssqa.model.DiagramComponent;
import ch.uzh.ifi.seal.ssqa.model.ModelFactory;
import ch.uzh.ifi.seal.ssqa.model.Revision;
import ch.uzh.ifi.seal.ssqa.model.Source;
import ch.uzh.ifi.seal.ssqa.model.UcmActivity;
import ch.uzh.ifi.seal.ssqa.preferences.PreferenceConstants;
import ch.uzh.ifi.seal.ssqa.storage.IStorage;
import ch.uzh.ifi.seal.ssqa.storage.StorageResult;
import ch.uzh.ifi.seal.ssqa.storage.TeneoHibernateStorage;
import ch.uzh.ifi.seal.ssqa.util.Table;

public class ChangeCoupling {
	private Table<String, String, Integer> table;
	
	private IStorage storage;
	
	public ChangeCoupling(){
		this.storage = new TeneoHibernateStorage();
		this.table = new Table<String, String, Integer>();
		
		StorageResult result = this.storage.executeUniqueSQLQuery("SELECT 1 FROM `ssqa`.`coupling` LIMIT 1");
		Number count = (Number) result.getResult();
		if(count != null && count.intValue() > 0){
			System.out.println("coupling from db");
			this.readOutSavedCouplings();
		} else {
			System.out.println("no db coupling found");
			this.readOutCouplings();
			this.persistCouplings();
		}
	}
	
	private void readOutCouplings(){
		StorageResult result = this.storage.executeListQuery("from UcmActivity");
		List<UcmActivity> activities = (List<UcmActivity>) result.getListResult();
		
		for(UcmActivity activity : activities){
			List<Revision> revisions = activity.getFileRevisons();
			// this has to be bigger than 1 because there are needed at least 2 entries.
			while(revisions.size() > 1 ){
				Revision checker = revisions.remove(0);
				for(Revision revision : revisions){
					if(checker.getFilePath() != null && revision.getFilePath() != null && !checker.getFilePath().equals(revision.getFilePath())){
						if(this.table.get(checker.getFilePath(), revision.getFilePath()) != null){
							Integer value = this.table.get(checker.getFilePath(), revision.getFilePath())+1;
							this.table.put(checker.getFilePath(), revision.getFilePath(), value);
							this.table.put(revision.getFilePath(), checker.getFilePath(), value);
						} else {
							this.table.put(checker.getFilePath(), revision.getFilePath(), 1);
							this.table.put(revision.getFilePath(), checker.getFilePath(), 1);
						}
					}
				}
			}
		}
		result.getSession().close();
	}
	
	private void persistCouplings(){
		List<String> rows = this.table.getRowLabels();
		List<String> cols = this.table.getColumnLabels();
		for(String row : rows){
			cols.remove(row);
			for(String col : cols){
				if(this.table.get(row, col) != null && this.table.get(row, col) != 0){
					Coupling coupling = ModelFactory.eINSTANCE.createCoupling();
					coupling.setFirstSource(row);
					coupling.setSecondSource(col);
					coupling.setValue(this.table.get(row, col));
					this.storage.saveOrUpdateEntity(coupling);
				}
			}
		}
	}
	
	private void readOutSavedCouplings(){
		IPreferenceStore store = SsqaPlugin.getDefault().getPreferenceStore();
		int threshold = store.getInt(PreferenceConstants.ANALYSIS_COUPLING_COUNT_THRESHOLD);
		StorageResult result = storage.executeListQuery("from Coupling where value > "+threshold +" ");
		List<Coupling> couplings = (List<Coupling>) result.getListResult();
		for(Coupling coupling : couplings){
			this.table.put(coupling.getFirstSource(), coupling.getSecondSource(), coupling.getValue());
		}
	}

	public Integer getCoupling(EObject object1 , EObject object2){
		if(object1 instanceof DiagramComponent && object2 instanceof DiagramComponent){
			return this.getDiagramComponentCoupling((DiagramComponent)object1, (DiagramComponent)object2);
		} else if (object1 instanceof Source && object2 instanceof Source){
			return this.getSourceCoupling((Source)object1, (Source)object2);
		}
		return 0;
	}
	
	private Integer getDiagramComponentCoupling(DiagramComponent component1 , DiagramComponent component2){
		Integer value = 0;
		StorageResult result = this.storage.executeListQuery("FROM Source WHERE diagrammapping='"+component2.getIdentifier()+"'");
		List<Source> sources = (List<Source>) result.getListResult();
		
		StorageResult result2 = this.storage.executeListQuery("FROM Source WHERE diagrammapping='"+component1.getIdentifier()+"'");
		List<Source> sources2 = (List<Source>) result2.getListResult();
		
		if(sources != null && sources2 != null && sources.size()>0 && sources2.size()>0){
			// this has to be bigger than 1 because there are needed at least 2 entries.
			while(sources.size() > 1){
				Source source = sources.remove(0);
				System.out.println(source.getProjectPath());
				for(Source source2 : sources2 ){
					value = value + this.getSourceCoupling(source, source2);
				}
			}
		}
		result.getSession().close();
		return value;
	}
	
	private Integer getSourceCoupling(Source source, Source source2){
		Integer value = 0;
	
		if(this.table.get(source.getProjectPath(), source2.getProjectPath()) != null && !this.isHeaderOf(source, source2)){
			value = value + this.table.get(source.getProjectPath(), source2.getProjectPath());
		} else if(this.table.get(source2.getProjectPath(), source.getProjectPath()) != null && !this.isHeaderOf(source, source2)){
			value = value + this.table.get(source2.getProjectPath(), source.getProjectPath());
		}
		return value;
	}
	
	private boolean isHeaderOf(Source source , Source source2){
		String name  = source.getName().substring(0, source.getName().lastIndexOf("."));
		String name2  = source2.getName().substring(0, source2.getName().lastIndexOf("."));
		System.out.println(name +" / "+ name2);
		return name.equals(name2);
	}
}
